package com.file.parser;

import com.file.bo.ResponseData;
import com.file.bo.mail.PSBC;
import com.file.bo.mail.PSBCTran;
import com.file.constant.ErrorCode;
import com.file.util.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.pdmodel.PDDocument;
import technology.tabula.*;
import technology.tabula.detectors.NurminenDetectionAlgorithm;
import technology.tabula.extractors.SpreadsheetExtractionAlgorithm;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.apache.poi.ss.usermodel.Sheet.TopMargin;

/**
 * 邮储银行流水pdf解析
 * @author anyspa
 */

@Slf4j
public class PSBCPdfParser extends BasePdfParser{

    public ResponseData<String> parsePSBCPdfToJson(String daId, String filePath) {
        log.info("parsePSBCPdfToJson started, daId:{}", daId);
        String json;

        try {
            PSBC psbc = parsePSBCPdf(filePath);
            json = JsonUtils.convertObjectToJson(psbc);
        } catch (Exception e) {
            log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_EXCEPTION.getCode(), daId, "", "", "parsePSBCPdfToJson1 failed", e);
            return new ResponseData<>(null, ErrorCode.FILE_PARSE_EXCEPTION.getCode(),
                    ErrorCode.FILE_PARSE_EXCEPTION.getMsg());
        }

        log.info("parsePSBCPdfToJson completed, daId:{}", daId);
        return new ResponseData<>(json, ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg());
    }

    private PSBC parsePSBCPdf(String filePath) {
        PSBC psbc = parsePSBCHeader(filePath);
        parseTrans(psbc, filePath);
        return psbc;
    }

    private PSBC parsePSBCHeader(String filePath) {
        PSBC psbc = new PSBC();
        String pdfHeaderText = parsePdfHeaderText(filePath);
        String accountNumber = pdfHeaderText.substring(pdfHeaderText.indexOf("卡号/账号：") + 6, pdfHeaderText.indexOf("户名："));
        String accountName = pdfHeaderText.substring(pdfHeaderText.indexOf("户名：") + 3, pdfHeaderText.indexOf("起止日期："));
        String transDetailPeriod;
        if (pdfHeaderText.contains("查询时间内总收入")) {
            transDetailPeriod = pdfHeaderText.substring(pdfHeaderText.indexOf("起止日期：") + 5, pdfHeaderText.indexOf("查询时间内总收入"));
            if (pdfHeaderText.contains("查询时间内总支出")) {
                String totalIncome = pdfHeaderText.substring(pdfHeaderText.indexOf("查询时间内总收入：") + 9, pdfHeaderText.indexOf("查询时间内总支出")).trim();
                String totalExpense = pdfHeaderText.substring(pdfHeaderText.indexOf("查询时间内总支出：") + 9, pdfHeaderText.indexOf("交易时间")).trim();
                psbc.setTotalIncome(totalIncome);
                psbc.setTotalExpense(totalExpense);
            } else {
                String totalIncome = pdfHeaderText.substring(pdfHeaderText.indexOf("查询时间内总收入：") + 9, pdfHeaderText.indexOf("交易时间")).trim();
                psbc.setTotalIncome(totalIncome);
            }
        } else {
            transDetailPeriod = pdfHeaderText.substring(pdfHeaderText.indexOf("起止日期：") + 5, pdfHeaderText.indexOf("交易时间"));
        }
        psbc.setTransDetailPeriod(transDetailPeriod);
        psbc.setAccountNumber(accountNumber.trim());
        psbc.setAccountName(accountName.trim());
        psbc.setTransDetailPeriod(transDetailPeriod.trim());

        return psbc;
    }

    private void parseTrans(PSBC psbc, String filePath) {
        List<PSBCTran> psbcTranList = new ArrayList<>();
        // 1. 读取文件
        File pdf = new File(filePath);

        // 2. pdfbox读取PDDocument
        try (PDDocument pdfDocument = PDDocument.load(pdf)) {

            // 3. tabula新建ObjectExtractor和NurminenDetectionAlgorithm，同时准备接收表格Rectangle的结构
            ObjectExtractor objectExtractor = new ObjectExtractor(pdfDocument);
            NurminenDetectionAlgorithm detectionAlgorithm = new NurminenDetectionAlgorithm();
            Map<Integer, List<Rectangle>> detectedTables = new HashMap<>();

            // 4. 获取每页的PageIterator
            PageIterator pages = objectExtractor.extract();

            // 5. 解析每页的Rectangle(table的位置)
            while (pages.hasNext()) {
                Page page = pages.next();
                List<Rectangle> tablesOnPage = detectionAlgorithm.detect(page);
                if (tablesOnPage.size() > 0) {
                    detectedTables.put(Integer.valueOf(page.getPageNumber()), tablesOnPage);
                }
            }

            // 6.通过table位置获取表格具体内容
            SpreadsheetExtractionAlgorithm bea = new SpreadsheetExtractionAlgorithm();

            // 如果单页pdf中有多个表格，则解析出来的List<Rectangle>会有多个对象
            for (Map.Entry<Integer, List<Rectangle>> entry : detectedTables.entrySet()) {
                Page page = objectExtractor.extract(entry.getKey());

                // 默认每页只有一个表格，因此获取第0个rectangle
                Rectangle rectangle = entry.getValue().get(0);
                rectangle.setBottom(rectangle.getBottom() + TopMargin);
                Page area = page.getArea(rectangle);

                List<Table> table = bea.extract(area);

                // 默认每页只有一个表格，因此获取第0个table
                Table t = table.get(0);
                if (t.getColCount() != 12) {
                    log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_EXCEPTION.getCode(), "", "", "", "PSBC pdf format changed");
                    throw new RuntimeException();
                }


                for (int i = 0; i < t.getRowCount(); i++) {
                    if (t.getCell(i,0).getText(false).contains("交易时间")) {
                        continue;
                    }
                    PSBCTran psbcTran = getTransactionByTable(t, i);
                    psbcTranList.add(psbcTran);
                }
                psbc.setPsbcTrans(psbcTranList);
            }
        }  catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private PSBCTran getTransactionByTable(Table t, int i) {
        PSBCTran psbcTran = new PSBCTran();
        psbcTran.setTransactionDate(t.getCell(i,0).getText(false));
        psbcTran.setSubAccount(t.getCell(i,1).getText(false));
        psbcTran.setAccountType(t.getCell(i,2).getText(false));
        psbcTran.setCurrency(t.getCell(i,3).getText(false));
        psbcTran.setCashExchange(t.getCell(i,4).getText(false));
        psbcTran.setTransactionBalance(t.getCell(i,5).getText(false));
        psbcTran.setAccountBalance(t.getCell(i,6).getText(false));
        psbcTran.setCounterPartyAccountName(t.getCell(i,7).getText(false));
        psbcTran.setCounterPartyAccountNumber(t.getCell(i,8).getText(false));
        psbcTran.setSummary(t.getCell(i,9).getText(false));
        psbcTran.setTransactionChannel(t.getCell(i,10).getText(false));
        psbcTran.setOutsideSysSeq(t.getCell(i,11).getText(false));

        return psbcTran;
    }

    public static void main(String[] args) {
        PSBCPdfParser psbcPdfParser = new PSBCPdfParser();
        String json = psbcPdfParser.parsePSBCPdfToJson("", "D:\\data\\file\\beehive-psbc\\电子版账户历史明细.pdf").getData();
        System.out.println(json);
//
//        json = psbcPdfParser.parsePSBCPdfToJson("", "D:\\data\\files\\PSBC\\mobiledetail_20230914171056991000648031889541_20230914.pdf").getData();
//        System.out.println(json);
//
//        json = psbcPdfParser.parsePSBCPdfToJson("", "D:\\data\\files\\PSBC\\mobiledetail_20230914171152991000648031435544_20230914.pdf").getData();
//        System.out.println(json);
//
//        json = psbcPdfParser.parsePSBCPdfToJson("", "D:\\data\\files\\PSBC\\mobiledetail_20230914171338991000648032274689_20230914.pdf").getData();
//        System.out.println(json);
//        System.out.println("--------------------------------------------------------------------------------------------------");
//        json = psbcPdfParser.parsePSBCPdfToJson("", "D:\\data\\files\\PSBC\\电子版账户历史明细.pdf").getData();
//        System.out.println(json);
    }
}
